define(['../vendor/kobako/pixi/anime.js',
    '../vendor/kobako/pixi/sprites.js',
    "../vendor/kobako/pixi/laser.js",
    './weapon.js',
    './monster.js'
], (anime, sprites, laser, weapon, monster_util) => {

    function bullet(sprite, texture_spawner) {
        const facing = sprite.facing
        const x = sprite.x
        const y = sprite.y
        const speed = 10
        const b = new PIXI.Sprite(texture_spawner.bullet1())
        b.vx = 0
        b.vy = 0
        switch (facing) {
            case 0:
                b.vy = -speed
                break
            case 1:
                b.vx = speed
                break
            case 2:
                b.vy = speed
                break
            case 3:
                b.vx = -speed
                break
        }
        b.x = x
        b.y = y

        anime.animation_sprite(b)

        return b
    }

    function boom(sprite, boom_texture_spawner) {
        const x = sprite.x, y = sprite.y
        const boom_texture = boom_texture_spawner.bullet1()
        const boom = new PIXI.Sprite(boom_texture)
        boom.x = x
        boom.y = y
        anime.once_anime_sprite(boom, () => {
            boom.destroy()
        })
        boom.set_ani('boom')
        return boom
    }

    function laser_sprite({ x, y }, texture_spawner) {
        const texture = texture_spawner.bullet1()
        const result = new PIXI.Sprite(texture)
        result.x = x
        result.y = y
        anime.animation_sprite(result)
        result.set_ani('laser')
        return result
    }

    //Because waht changed the facing-point is uncertain, using a function to wrap the change
    function setting_facing_point(player) {
        // player.facing_point.x = player.mouse.x
        // player.facing_point.x = player.mouse.y

        // if (player.kb.w_down) {
        //     player.facing_point.x = player.x
        //     player.facing_point.y = player.y - 1
        // }else if(player.kb.s_down){
        //     player.facing_point.x = player.x
        //     player.facing_point.y = player.y + 1
        // }

        // if (player.kb.a_down) {
        //     player.facing_point.x = player.x - 1
        // }else if(player.kb.d_down){
        //     player.facing_point.x = player.x + 1
        // }
    }

    function first_emit(player) {
        return player.emitting && !player.weapon.pressing
    }

    function pressing_emit(player) {
        return player.emitting && player.weapon.pressing
    }

    function released_emit(player) {
        return !player.pressing
    }

    /**
     * A function abstract the concept of emitting bullets
     */
    function emit_process(player, booms, bullets, logger) {
        player.weapon.cooldown_update()

        if (first_emit(player)) {
            player.weapon.pressing = true
            if (player.weapon.is_cooldown_over()) {
                //Check the type
                if (player.weapon.type == 'laser') {
                    player.weapon.spawn_bullets().forEach(b => {
                        booms.addChild(b)
                        player.weapon.bullets.push(b)
                    })
                } else if (player.weapon.type == 'bullet') {
                    player.weapon.spawn_bullets().forEach(b => {
                        //check if is laser
                        bullets.addChild(b)
                        player.weapon.bullets.push(b)
                    })
                }
            } else {
                console.warn('The weapon is not cooldown!')
                logger.add('The ' + player.weapon.name + ' is not cooldowned!')
            }
        } else if (pressing_emit(player)) {
            player.weapon.ajust_bullets()
        } else if (released_emit(player)) {
            player.weapon.pressing = false
            player.weapon.bullets = []
        }
    }

    function bullets_life_circle(world) {
        // ## Bullets' lives circles
        // Bullets move
        world.bullets.children.forEach(b => {
            sprites.move_by_velocity(b)
        })
        // Boom when collide sprite
        world.bullets.children.forEach(b => {
            //Crash the stone
            const stone = world.stones.find(stone => {
                return sprites.is_collided(b, stone)
            })

            if (stone != null) {
                //Add a boom anime
                world.booms.addChild(boom(b, world.texture_spawner))
                b.destroy()
                stone.destroy()
            }
        })
        // Remove when collide bound
        world.bullets.children.filter(b => sprites.is_collide_bound(b, world.bound)).forEach(b => {
            b.destroy()
        })
    }

    return {
        update: (world) => {
            const player = world.player
            // Player move
            if (sprites.no_stone_in_the_way(player, world.stones)) {
                sprites.move_by_velocity(player)
            }

            // Monster AI
            world.monsters.children.forEach(monster => {
                monster.update(world.player)
            })

            // Monster move
            world.monsters.children.forEach(monster => {
                if (sprites.no_stone_in_the_way(monster, world.stones)) {
                    sprites.move_by_velocity(monster)
                }
            })

            // Setting facing point
            setting_facing_point(player)

            emit_process(player, world.booms, world.bullets, world.logger)

            bullets_life_circle(world)
        },
        init_weapon_system: weapon.init_weapon_system,
        init(world) {
            //Spawn monsters
            monster_util.spawn_level_one_monsters(world.bound, world.stones, 5, world.texture_spawner, world.bullets, world.booms).forEach(m => {
                world.monsters.addChild(m)
            })
        }
    }
})